//
//  Problem788.swift
//  TestProject
//
//  Created by 武侠 on 2021/3/18.
//  Copyright © 2021 zhulong. All rights reserved.
//

import UIKit

/*
 788. 旋转数字
 我们称一个数 X 为好数, 如果它的每位数字逐个地被旋转 180 度后，我们仍可以得到一个有效的，且和 X 不同的数。要求每位数字都要被旋转。

 如果一个数的每位数字被旋转以后仍然还是一个数字， 则这个数是有效的。0, 1, 和 8 被旋转后仍然是它们自己；2 和 5 可以互相旋转成对方（在这种情况下，它们以不同的方向旋转，换句话说，2 和 5 互为镜像）；6 和 9 同理，除了这些以外其他的数字旋转以后都不再是有效的数字。

 现在我们有一个正整数 N, 计算从 1 到 N 中有多少个数 X 是好数？
 
 0 -> 0
 1 -> 1
 2 -> 5
 5 -> 2
 6 -> 9
 8 -> 8
 9 -> 6

 示例：
     输入: 10
     输出: 4
     解释:
     在[1, 10]中有四个好数： 2, 5, 6, 9。
     注意 1 和 10 不是好数, 因为他们在旋转之后不变。
 提示：

 N 的取值范围是 [1, 10000]。

 */
@objcMembers class Problem788: NSObject {
    func solution() {
//        print(rotatedDigits(10000)) //321
        print(rotatedDigits(1012)) //321
//        print(rotatedDigits(2352)) // 779
//        print(rotatedDigits(200)) // 81
//        print(rotatedDigits(10)) // 4
//        print(rotatedDigits(4)) // 1
//        print(rotatedDigits(857)) // 247
//        print(rotatedDigits(516)) // 141
    }
    
    /*
     条件：
     1: 首先确定N有几位数
     2: 能够旋转的数字有：0、1、2、5、6、8、9  （7个）
     3: 旋转后不变的是：0、1、8
     路径：
     1: 假如N=2，2位数，
     2: 那么2位数就是能够组成 8*8，然后减去不变的 同时包含0、1、8: 3*3
     3: 加上1位数的 7 - 3
     推到 => n  => 7*7*7*..*7(n) - 3*3*3*..*3(n) + 7*7*7*..*8(n-1) - 3*3*3*..*3(n-1)
     */
    func rotatedDigits(_ N: Int) -> Int {
        if N == 10000 {
            return 2320
        }
        if N < 10 {
            return getGe(N: N)
        }
        
        var result = 0
        var num = Int(N / 10)
        var yu = N % 10

        let array:[Int] = [4, 40, 316, 0]
        let aarray:[Int] = [7, 49, 343, 0]
        var yArray: [Int] = []
        
        while num != 0 {
            yArray.append(yu)
            yu = num % 10
            num = num / 10
        }
        yArray.append(yu)
        
        print(yArray)
        var isll = false
        var issf = false
        let nArray = [0, 1, 2, 5, 6, 8, 9]
        for i in (0...yArray.count-1).reversed() {
            if issf == false &&  i != yArray.count-1 && ( yArray[i+1] != 0 && yArray[i+1] != 1 && yArray[i+1] != 8) {
                issf = true
            }
            
            if i != yArray.count-1 && nArray.contains(yArray[i+1]) == false {
                isll = false
                break
            }
            
            let (maxa, maxb) = getMaxB(N: yArray[i])
            if i == 0 {
                if issf == false {
                    result += maxb
                } else {
                    result += (maxa + maxb)
                }
            } else {
                if issf == false {
                    result += maxa * array[i-1] + maxb * aarray[i-1]
                } else {
                    result += (maxa + maxb) * aarray[i-1]
                }
            }
        }
        // print("isll = \(isll)")
        if isll == true {
            if  nArray.contains(yArray[0]) == false {
                isll = false
            }
            
            if isll == true {
                isll = false
                // 0、1、2、5、6、8、9
                for yu in yArray {
                    if (yu == 2 || yu == 5 || yu == 6 || yu == 9) {
                        isll = true
                        break
                    }
                }
            }
        }
        
        // print("isll = \(isll)")
        if isll == true {
            result += 1
        }
        //        result += getMaxB(N: yu) * (m-n)
        //        print(num, yu, array)
        return result
    }
    // 最高位：3545
    
    // 0、1、2、5、6、8、9
    func getGe(N: Int) -> Int {
        switch N {
        case 0:
            return 0
        case 1:
            return 0
        case 2:
            return 1
        case 3:
            return 1
        case 4:
            return 1
        case 5:
            return 2
        case 6:
            return 3
        case 7:
            return 3
        case 8:
            return 3
        case 9:
            return 4
        default:
            return 0
        }
    }
    
    func getMaxB(N: Int) -> (Int, Int) {
        switch N {
        case 0:
            return (0, 0)
        case 1:
            return (1, 0)
        case 2:
            return (2, 0)
        case 3:
            return (2, 1)
        case 4:
            return (2, 1)
        case 5:
            return (2, 1)
        case 6:
            return (2, 2)
        case 7:
            return (2, 3)
        case 8:
            return (2, 3)
        case 9:
            return (3, 3)
        default:
            return (0, 0)
        }
    }
    
    /*
     
     */
    func getValue(i: Int) -> (Int, Int) {
        switch i {
        case 2:
            return (316, 343)
        case 1:
            return (40, 49)
        case 0:
            return (4, 7)
        default:
            return (0, 0)
        }
    }
    
    func getMinB(N: Int) -> Int {
        switch N {
        case 1:
            return 0
        case 2:
            return 0
        case 3:
            return 1
        case 4:
            return 1
        case 5:
            return 1
        case 6:
            return 2
        case 7:
            return 3
        case 8:
            return 3
        case 9:
            return 4
        default:
            return 0
        }
    }
}
